#include "Camera.h"
#include <iostream>

using namespace std;

namespace glow
{

Camera::Camera()
{
	setDefaultKeyMap();
	reset();
}

Camera::Camera (Vector3d pos)
{
	setDefaultKeyMap();
	reset();
	_position = pos;
}

Camera::~Camera(){}

void Camera::setDefaultKeyMap()
{
	_kmap["forward"] = 'Z';
	_kmap["backward"] = 'S';
	_kmap["left"] = 'Q';
	_kmap["right"] = 'D';
	_kmap["boost"] = GLFW_KEY_LSHIFT;
}

void Camera::setKeyMap(const KeyMap &kmap)
{
	_kmap = kmap;
}

const Vector3d &Camera::getPosition() const {
	return _position;
}

const Vector3d &Camera::getAngle() const {
	return _angle;
}

const Vector3d &Camera::getTarget() const {
	return _target;
}

void Camera::setPosition(Vector3d pos){
	_position = pos;
}

void Camera::setAngle(Vector3d ang){
	_angle = ang;
}

void Camera::setTarget(Vector3d targ){
	_target = targ;
}

void Camera::reset()
{
	_speed = 1.0;
    _sensivity = 1.0;
    
    _forward = Vector3d(0.0, 0.0, 1.0);
    _phi = 0;
    _theta = 0;
    
    _position = Vector3d(0, 0, 0);
	_angle = Vector3d(0.0, 1.0, 0.0);
	_target = Vector3d(0.0, 0.0, 0.0);
	
	VectorsFromAngles();
	
	_now = 0;
    _start_time = 0;
    _time_step = 0;
}

void Camera::setSpeed(double speed)
{
    _speed = speed;
}

void Camera::setSensivity(double sensivity)
{
    _sensivity = sensivity;
}

void Camera::lookAt(Vector3d pos, Vector3d targ, Vector3d ang)
{
	_position = pos;
	_angle = ang;
	_target = targ;
	gluLookAt(pos.x, pos.y, pos.z,targ.x, targ.y, targ.z, ang.x, ang.y, ang.z);
}

void Camera::look()
{
	gluLookAt(_position.x, _position.y, _position.z, _target.x, _target.y, _target.z, _angle.x, _angle.y, _angle.z);
}

void Camera::VectorsFromAngles()
{
    static const Vector3d up(0,1,0);
    if (_phi > 89)
        _phi = 89;
    else if (_phi < -89)
        _phi = -89;
    double r_temp = cos(_phi*M_PI/180);

    _forward.z = r_temp*sin(_theta*M_PI/180);
    _forward.x = -r_temp*cos(_theta*M_PI/180);
    _forward.y = sin(_phi*M_PI/180);

    _left = up.crossProduct(_forward);
    _left.normalize();

    _target = _position + _forward;
}

void Camera::getEvent()
{
	_keystates["forward"] = EventManager::getInstance()->isKeyDown(_kmap["forward"]);
    _keystates["backward"] = EventManager::getInstance()->isKeyDown(_kmap["backward"]);
    _keystates["strafe_left"] = EventManager::getInstance()->isKeyDown(_kmap["left"]);
    _keystates["strafe_right"] = EventManager::getInstance()->isKeyDown(_kmap["right"]);
    _keystates["boost"] = EventManager::getInstance()->isKeyDown(_kmap["boost"]);

    _theta -= EventManager::getInstance()->getRelMouseX()*_sensivity;
    _phi -= EventManager::getInstance()->getRelMouseY()*_sensivity;

    VectorsFromAngles();
}

void Camera::animate()
{
	_now = glfwGetTime();
    _time_step = _now - _start_time;
    _start_time = _now;

    double realspeed = (_keystates["boost"])?10*_speed:_speed;
    if (_keystates["forward"])
        _position += _forward * (realspeed * _time_step);
    if (_keystates["backward"])
        _position -= _forward * (realspeed * _time_step);
    if (_keystates["strafe_left"])
        _position += _left * (realspeed * _time_step);
    if (_keystates["strafe_right"])
        _position -= _left * (realspeed * _time_step);

    _target = _position + _forward;
}

}
